<?php

namespace common\models;

use common\logics\MemberLogic;
use common\logics\RewardLogic;
use common\models\actor\Actor;
use common\models\member\Member;
use common\models\user\UserAccount;
use common\models\user\UserConnect;
use common\models\user\UserTrend;
use Yii;
use yii\db\AfterSaveEvent;
use yii\web\IdentityInterface;
use yii\validators\EmailValidator;
use common\validators\MobileValidator;
use common\db\ActiveRecord;
use common\helpers\Url;
use common\helpers\StringHelper;
use common\helpers\ArrayHelper;
use common\models\user\UserMeta;
use common\models\app\AppToken;

/**
 * 基础用户账号信息模型
 *
 * @property int $id
 * @property int $user_id
 * @property string $username
 * @property string $nickname
 * @property string $mobile
 * @property string $mobile_hash
 * @property string $email
 * @property string $avatar
 * @property string $auth_key
 * @property string $password_hash
 * @property string $password_reset_token
 * @property string $ip
 * @property int $status
 * @property string $created_at
 * @property string $updated_at
 * @property string $deleted_at
 * @property string $usernameByMobile
 * @property UserMeta $meta
 * @property null $uniqueNickname
 * @property string $password
 * @property Member $member
 * @property MemberLogic $avalidMember
 * @property int $discount
 * @property int $collects
 * @property array $stats
 * @property string $experiences
 * @property \yii\db\ActiveQuery $favorites
 * @property type $userBranch
 * @property UserTrend $userTrend
 * @property string $credits
 * @property UserAccount $userAccount
 * @property UserConnect[] $connects
 * @property mixed $openid
 * @property UserAccount $account
 * @property string $authKey
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
class BaseUser extends ActiveRecord implements IdentityInterface
{

    /**
     * 默认用户状态
     */
    const STATUS_DEFAULT = 0;

    /**
     * 激活用户状态
     */
    const STATUS_ACTIVE = 10;

    /**
     * Token过期时间 15天
     */
    const TOKEN_DURATION = 12960000;

    /**
     * 用户数据表表名
     *
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%user}}';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            ['status', 'default', 'value' => static::STATUS_ACTIVE],
            ['status', 'in', 'range' => [static::STATUS_ACTIVE, static::STATUS_DEFAULT]],
        ];
    }

    /**
     * @inheritdoc
     */
    public static function findIdentity($id)
    {
        return static::findOne([
            'id' => $id,
            'status' => static::STATUS_ACTIVE,
        ]);
    }

    /**
     * @inheritdoc
     */
    public static function findIdentityByAccessToken($token, $type = null)
    {
        /* @var \common\base\Security $security */
        $security = Yii::$app->getSecurity();
        $accessToken = $security->decryptDataByKey($token);
        if ($accessToken === false) {
            return null;
        }
        return AppToken::find()->andWhere([
            'and',
            ['access_token' => $accessToken],
            ['>', 'expired_at', time()],
        ])->one();
    }

    /**
     * 调用认证的函数，下面会说到
     * 查询数据库中有没有存在这个token
     *
     * @param $accessToken
     * @param $type
     * @return array|AppToken|\yii\db\ActiveRecord|IdentityInterface|null
     */
    public function loginByAccessToken($accessToken, $type)
    {
        return static::findIdentityByAccessToken($accessToken, $type);
    }

    /**
     * 根据用户名查询用户信息
     *
     * @param string $username 用户名
     * @return BaseUser|null
     */
    public static function findByUsername($username)
    {
        return static::findOne([
            'username' => $username,
            'status' => static::STATUS_ACTIVE,
        ]);
    }

    /**
     * 根据手机号查询用户信息
     *
     * @param string $mobile
     * @return BaseUser|null
     */
    public static function findByMobile($mobile)
    {
        /* @var \common\base\Security $security */
        $security = Yii::$app->getSecurity();
        $entra = $security->generatePrivateKey($mobile);
        return static::findOne([
            'mobile' => $entra,
            'status' => static::STATUS_ACTIVE,
        ]);
    }

    /**
     * 通过用户名、手机号或者邮箱查询用户
     *
     * @param string $account 用户名、手机号或者邮箱
     * @return array|BaseUser|\yii\db\ActiveRecord|null
     * @throws \yii\base\InvalidConfigException
     */
    public static function findByAccount($account)
    {
        $query = static::find()->active(static::STATUS_ACTIVE);
        $condition = [
            'or',
            ['username' => $account],
        ];
        if (is_numeric($account)) {
            $valid = new MobileValidator();
            if ($valid->validate($account)) {
                /* @var \common\base\Security $security */
                $security = Yii::$app->getSecurity();
                $mobile = $security->generatePrivateKey($account);
                $condition[] = ['mobile' => $mobile];
            }
        }
        if (strpos($account, '@') !== false) {
            $valid = new EmailValidator();
            if ($valid->validate($account)) {
                $condition[] = ['email' => $account];
            }
        }
        return $query->andWhere($condition)->one();
    }

    /**
     * 获取账号密码重置token
     *
     * @param string $token password reset token
     * @return BaseUser|null
     */
    public static function findByPasswordResetToken($token)
    {
        if (!static::isPasswordResetTokenValid($token)) {
            return null;
        }
        return static::findOne([
            'password_reset_token' => $token,
            'status' => self::STATUS_ACTIVE,
        ]);
    }

    /**
     * 判断用户密码重置token是否有效
     *
     * @param string $token password reset token
     * @return bool
     */
    public static function isPasswordResetTokenValid($token)
    {
        if (empty($token)) {
            return false;
        }
        $timestamp = (int)substr($token, strrpos($token, '_') + 1);
        $expire = ArrayHelper::getValue(Yii::$app->params, 'user.passwordResetTokenExpire', 86400);
        return $timestamp + $expire >= time();
    }

    /**
     * @inheritdoc
     */
    public function getId()
    {
        return $this->getPrimaryKey();
    }

    /**
     * @inheritdoc
     */
    public function getAuthKey()
    {
        return $this->auth_key;
    }

    public function getPortrait()
    {
        return Url::attach($this->avatar);
    }

    /**
     * @inheritdoc
     */
    public function validateAuthKey($authKey)
    {
        return $this->getAuthKey() === $authKey;
    }

    /**
     * 验证账号密码是否正确
     *
     * @param string $password password to validate
     * @return bool
     */
    public function validatePassword($password)
    {
        if ($this->password_hash) {
            return Yii::$app->security->validatePassword($password, $this->password_hash);
        }
        return false;
    }

    public function getActor()
    {
        return $this->hasOne(Actor::class, ['user_id' => 'id']);
    }

    public function getActorId()
    {
        return $this->actor ? $this->actor->id : 0;
    }

    /**
     * 设置密码
     *
     * @param string $password
     * @throws \yii\base\Exception
     */
    public function setPassword($password)
    {
        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
    }

    /**
     * 根据手机号自动生成系统唯一用户名
     *
     * @param string $mobile
     */
    public function setUsernameByMobile($mobile)
    {
        $this->username = Url::toShort($mobile . microtime());
        $this->setMobile($mobile);
    }

    /**
     * 根据OAuth2.0第三方平台的openid生成系统唯一用户名
     *
     * @param string $client 第三方平台
     * @param string $openid openid
     */
    public function setUsernameByOpenid($client, $openid)
    {
        $this->username = Url::toShort($client . $openid . microtime());
    }

    /**
     * 设置用户头像
     *
     * @param null $avatar
     * @return mixed|string|null
     */
    public function setAvatar($avatar = null)
    {
        if ($avatar === null) {
            $avatar = ArrayHelper::getValue(Yii::$app->params, 'defaultImages.user_avatar');
        }
        return $this->avatar = $avatar ?: '/assets/avatar/default.png';
    }

    /**
     * 设置用户昵称
     *
     * @param null $nickname
     */
    public function setUniqueNickname($nickname = null)
    {
        if ($nickname) {
            $rand = '';
            do {
                $exists = static::find()->where(['nickname' => $nickname . $rand])->exists();
                if ($exists) {
                    $rand = Url::toShort(microtime(true));
                }
            } while ($exists);
            $this->nickname = $nickname;
        }
    }

    /**
     * 设置手机号（自动加密）
     *
     * @param string $mobile 手机号
     */
    public function setMobile($mobile)
    {
        if ($mobile) {
            /* @var $security \common\base\Security */
            $security = Yii::$app->security;
            $this->mobile = $security->generatePrivateKey($mobile);
            $this->mobile_hash = $security->encryptMaster($mobile);
        }
    }

    /**
     * 手机号解密
     *
     * @param boolean $mask 是否屏蔽手机号部分信息
     * @return string|string[]|null
     */
    public function decryptMobile($mask = true)
    {
        $mobile = '';
        if ($this->mobile_hash) {
            /* @var $security \common\base\Security */
            $security = Yii::$app->security;
            $mobile = $security->decryptMaster($this->mobile_hash);
            if ($mask !== false) {
                return StringHelper::maskChar($mobile, 3, 2);
            }
        }
        return $mobile;
    }

    /**
     * 生成auth_key
     *
     * @throws \yii\base\Exception
     */
    public function generateAuthKey()
    {
        $this->auth_key = Yii::$app->security->generateRandomString();
    }

    /**
     * 生成密码重置token
     *
     * @throws \yii\base\Exception
     */
    public function generatePasswordResetToken()
    {
        $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
    }

    /**
     * 移除密码重置token
     */
    public function removePasswordResetToken()
    {
        $this->password_reset_token = null;
    }

    /**
     * 获取用户基础信息
     *
     * @return \yii\db\ActiveQuery
     */
    public function getMeta()
    {
        return $this->hasOne(UserMeta::class, ['id' => 'id']);
    }

    /**
     * 获取用户积分等信息
     *
     * @return \yii\db\ActiveQuery
     */
    public function getUserTrend()
    {
        return $this->hasOne(UserTrend::class, ['user_id' => 'id']);
    }

    /**
     * 获取用户积分等信息
     *
     * @return \yii\db\ActiveQuery
     */
    public function getUserAccount()
    {
        return $this->hasOne(UserAccount::class, ['user_id' => 'id'])->andWhere([
            'type' => UserAccount::TYPE_CREDIT
        ]);
    }

    /**
     * 获取收藏的商品
     *
     * @return \yii\db\ActiveQuery
     */
    public function getFavorites()
    {
        return $this->hasOne(\common\models\shop\ShopFavorite::className(), ['user_id' => 'id']);
    }

    /**
     * 获取收藏的商品数
     *
     * @return integer
     */
    public function getCollects()
    {
        return $this->getFavorites()->count();
    }

    /**
     * 经验值
     *
     * @return string
     */
    public function getExperiences()
    {
        if ($this->userTrend) {
            return $this->userTrend->experience;
        }
        return '-';
    }

    /**
     * 经验值
     *
     * @return string
     */
    public function getCredits()
    {
        if ($this->userAccount) {
            if ($this->userAccount->isAvaliable()) {
                return $this->userAccount->current;
            }
            return '-';
        }
        return '-';
    }

    /**
     * 获取收藏的商品数
     *
     * @return array
     */
    public function getStats()
    {
        return [
            'collects' => $this->collects,
            'experiences' => $this->experiences,
            'credits' => $this->credits,
        ];
    }

    /**
     * 获取会员信息
     *
     * @return \yii\db\ActiveQuery
     */
    public function getUserBranch()
    {
        return $this->hasOne(\common\models\user\UserBranch::className(), ['user_id' => 'id']);
    }

    /**
     * 获取会员信息
     *
     * @return \yii\db\ActiveQuery
     */
    public function getMember()
    {
        return $this->hasOne(Member::class, ['user_id' => 'id']);
    }

    /**
     * 获取会员信息
     *
     * @return \yii\db\ActiveQuery
     */
    public function getConnects()
    {
        return $this->hasMany(UserConnect::class, ['user_id' => 'id']);
    }

    /**
     * 获取用户OPENID
     *
     * @param string $client
     * @return string
     */
    public function getOpenid($client = UserConnect::CLIENT_WECHAT_ACCOUNT)
    {
        $list = ArrayHelper::map($this->connects, 'client', 'openid');
        return ArrayHelper::getValue($list, $client);
    }

    /**
     * 获取会员信息
     *
     * @return \yii\db\ActiveQuery
     */
    public function getAvalidMember()
    {
        return $this->hasOne(MemberLogic::class, ['user_id' => 'id'])->active(Member::STATUS_ACTIVE)->andWhere([
            'audit_status' => Member::AUDIT_STATUS_FINISH,
        ])->andWhere([
            'or',
            ['expired_at' => 0],
            ['>', 'expired_at', time()],
        ]);
    }

}
